#!/bin/bash

if [ "$1" = "-h" -o "$1" = "--help" ]; then
echo "Usage: ./configure [options]"
echo ""
echo "available options:"
echo ""
echo "  --help                   print this message"
echo "  --enable-avs             enables avisynth plugin support (windows only)"
echo "  --enable-debug           adds -g, doesn't strip"
echo "  --enable-gprof           adds -pg, doesn't strip"
echo "  --enable-pic             build position-independent code"
echo "  --enable-shared          build libffms2.so"
echo "  --enable-postproc        build with postproc support (requires libpostproc)"
echo "  --extra-cppflags=EFLAGS  add EFLAGS to CPPFLAGS"
echo "  --extra-cflags=ECFLAGS   add ECFLAGS to CFLAGS"
echo "  --extra-cxxflags=EFLAGS  add EFLAGS to CXXFLAGS"
echo "  --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS"
echo "  --extra-soflags=ESOFLAGS add ESOFLAGS to SOFLAGS"
echo "  --host=HOST              build programs to run on HOST"
echo "  --cross-prefix=PREFIX    use PREFIX for compilation tools"
echo "  --sysroot=SYSROOT        root of cross-build tree"
echo ""
exit 1
fi

log_check() {
    echo -n "checking $1... " >> config.log
}

log_ok() {
    echo "yes" >> config.log
}

log_fail() {
    echo "no" >> config.log
}

log_msg() {
    echo "$1" >> config.log
}

cpp_check() {
    log_check "whether $3 is true"
    rm -f conftest.c
    [ -n "$1" ] && echo "#include <$1>" > conftest.c
    echo -e "#if !($3) \n#error $4 \n#endif " >> conftest.c

    if $CC conftest.c $CPPFLAGS $2 -E -o conftest >conftest.log 2>&1; then
        res=$?
        log_ok
    else
        res=$?
        log_fail
        log_msg "--------------------------------------------------"
        cat conftest.log >> config.log
        log_msg "--------------------------------------------------"
    fi
    return $res
}

cc_check() {
    if [ -z "$3" ]; then
        if [ -z "$1$2" ]; then
            log_check "whether $CC works"
        elif [ -z "$1" ]; then
            log_check "for $2"
        else
            log_check "for $1"
        fi
    elif [ -z "$1" ]; then
        log_check "whether $CC supports $3"
    else
        log_check "for $3 in $1";
    fi
    rm -f conftest.c
    [ -n "$1" ] && echo "#include <$1>" > conftest.c
    echo "int main () { $3 return 0; }" >> conftest.c
    if $CC conftest.c $CPPFLAGS $CFLAGS $2 $LDFLAGS -o conftest >conftest.log 2>&1; then
        res=$?
        log_ok
    else
        res=$?
        log_fail
        log_msg "Failed commandline was:"
        log_msg "--------------------------------------------------"
        log_msg "$CC conftest.c $CFLAGS $LDFLAGS $2"
        cat conftest.log >> config.log
        log_msg "--------------------------------------------------"
    fi
    return $res
}

cxx_check() {
    if [ -z "$3" ]; then
        if [ -z "$1$2" ]; then
            log_check "whether $CXX works"
        elif [ -z "$1" ]; then
            log_check "for $2"
        else
            log_check "for $1"
        fi
    elif [ -z "$1" ]; then
        log_check "whether $CXX supports $3"
    else
        log_check "for $3 in $1";
    fi
    rm -f conftest.c
    [ -n "$1" ] && echo "#include <$1>" > conftest.c
    echo "int main () { $3 return 0; }" >> conftest.c
    if $CXX conftest.c $CPPFLAGS $CXXFLAGS $2 $LDFLAGS -o conftest >conftest.log 2>&1; then
        res=$?
        log_ok
    else
        res=$?
        log_fail
        log_msg "Failed commandline was:"
        log_msg "--------------------------------------------------"
        log_msg "$CXX conftest.c $CXXFLAGS $LDFLAGS $2"
        cat conftest.log >> config.log
        log_msg "--------------------------------------------------"
    fi
    return $res
}

define() {
    echo "#define $1$([ -n "$2" ] && echo " $2" || echo " 1")" >> config.h
}

die() {
    log_msg "DIED: $@"
    echo "$@"
    exit 1
}

rm -f config.h config.mak config.log ffms.pc ffmsdll.rc.h ffmsindexexe.rc.h conftest*

prefix='/usr/local'
exec_prefix='${prefix}'
bindir='${exec_prefix}/bin'
libdir='${exec_prefix}/lib'
includedir='${prefix}/include'
DEVNULL='/dev/null'

avs="no"
debug="no"
gprof="no"
pic="no"
shared="no"
postproc="no"

CPPFLAGS="$CPPFLAGS -I. -Iinclude -D_FILE_OFFSET_BITS=64"
CFLAGS="$CFLAGS -Wall"
CXXFLAGS="$CXXFLAGS -Wall -D__STDC_CONSTANT_MACROS"
LDFLAGS="$LDFLAGS"
SOFLAGS="$SOFLAGS"
HAVE_GETOPT_LONG=1
cross_prefix=""

EXE=""

# parse options

for opt do
    optarg="${opt#*=}"
    case "$opt" in
        --prefix=*)
            prefix="$optarg"
            ;;
        --exec-prefix=*)
            exec_prefix="$optarg"
            ;;
        --bindir=*)
            bindir="$optarg"
            ;;
        --libdir=*)
            libdir="$optarg"
            ;;
        --includedir=*)
            includedir="$optarg"
            ;;
        --enable-avs)
            avs="yes"
            ;;
        --enable-postproc)
            postproc="yes"
            ;;
        --extra-cppflags=*)
            CPPFLAGS="$CPPFLAGS ${opt#--extra-cppflags=}"
            ;;
        --extra-cflags=*)
            CFLAGS="$CFLAGS ${opt#--extra-cflags=}"
            ;;
        --extra-cxxflags=*)
            CXXFLAGS="$CXXFLAGS ${opt#--extra-cxxflags=}"
            ;;
        --extra-ldflags=*)
            LDFLAGS="$LDFLAGS ${opt#--extra-ldflags=}"
            ;;
        --extra-soflags=*)
            SOFLAGS="$SOFLAGS ${opt#--extra-soflags=}"
            ;;
        --enable-debug)
            debug="yes"
            ;;
        --enable-gprof)
            CFLAGS="$CFLAGS -pg"
            LDFLAGS="$LDFLAGS -pg"
            gprof="yes"
            ;;
        --enable-pic)
            pic="yes"
            ;;
        --enable-shared)
            shared="yes"
            ;;
        --host=*)
            host="${opt#--host=}"
            ;;
        --cross-prefix=*)
            cross_prefix="${opt#--cross-prefix=}"
            ;;
        --sysroot=*)
            CFLAGS="$CFLAGS --sysroot=${opt#--sysroot=}"
            LDFLAGS="$LDFLAGS --sysroot=${opt#--sysroot=}"
            ;;
        *)
            echo "Unknown option $opt, ignored"
            ;;
    esac
done

CC="${CC-${cross_prefix}gcc}"
CXX="${CXX-${cross_prefix}g++}"
AR="${AR-${cross_prefix}ar}"
RANLIB="${RANLIB-${cross_prefix}ranlib}"
STRIP="${STRIP-${cross_prefix}strip}"
RC=""

if [ -z "$host" -a -z "$cross_prefix" ]; then    
    host=`./config.guess`
else
    host="${cross_prefix%%-}"
fi
# normalize a triplet into a quadruplet
host=`./config.sub $host`

# split $host
host_cpu="${host%%-*}"
host="${host#*-}"
host_vendor="${host%%-*}"
host_os="${host#*-}"

case $host_os in
  beos*)
    SYS="BEOS"
    ;;
  darwin*)
    SYS="MACOSX"
    if [ "$pic" = "no" ]; then
        cc_check "" -mdynamic-no-pic && CFLAGS="$CFLAGS -mdynamic-no-pic"
    fi
    ;;
  freebsd*)
    SYS="FREEBSD"
    ;;
  kfreebsd*-gnu)
    SYS="FREEBSD"
    ;;
  netbsd*)
    SYS="NETBSD"
    ;;
  openbsd*)
    SYS="OPENBSD"
    ;;
  *linux*)
    SYS="LINUX"
    ;;
  cygwin*)
    SYS="MINGW"
    EXE=".exe"
    DEVNULL="NUL"
    pic="no"
    if cc_check "" -mno-cygwin; then
        CFLAGS="$CFLAGS -mno-cygwin"
        CXXFLAGS="$CXXFLAGS -mno-cygwin"
        LDFLAGS="$LDFLAGS -mno-cygwin"
    fi
    ;;
  mingw*)
    SYS="MINGW"
    EXE=".exe"
    DEVNULL="NUL"
    ;;
  sunos*|solaris*)
    SYS="SunOS"
    ;;
  *)
    die "Unknown system $host, edit the configure"
    ;;
esac

! cc_check && die "no working c compiler found
! cxx_check && die "no working c++ compiler found

if cc_check '' -std=gnu99 ; then
    CFLAGS="$CFLAGS -std=gnu99"
elif cc_check '' -std=c99 ; then
    CFLAGS="$CFLAGS -std=c99"
    CPPFLAGS="$CPPFLAGS -D_POSIX_C_SOURCE=200112L -D_BSD_SOURCE -U__STRICT_ANSI__"
fi

if cpp_check '' '' "defined(_WIN32)" ; then
    pic="no"
else
    avs="no"
fi

#COM functions on windows
cc_check "objbase.h" "-lole32" "CoUninitialize();" && LDFLAGS="$LDFLAGS -lole32"

#find ffmpeg
if ${cross_prefix}pkg-config --exists libavformat libavcodec libswscale libavutil 2>$DEVNULL; then
    FFMPEG_LIBS="$FFMPEG_LIBS $(${cross_prefix}pkg-config --libs libavformat libavcodec libswscale libavutil)"
    FFMPEG_CFLAGS="$FFMPEG_CFLAGS $(${cross_prefix}pkg-config --cflags libavformat libavcodec libswscale libavutil)"
fi
# optional libpostproc
if [ "$postproc" = "yes" ] && ${cross_prefix}pkg-config --exist libpostproc 2>$DEVNULL; then
    FFMPEG_LIBS="$FFMPEG_LIBS $(${cross_prefix}pkg-config --libs libpostproc)"
    FFMPEG_CFLAGS="$FFMPEG_CFLAGS $(${cross_prefix}pkg-config --cflags libpostproc)"
fi
# libavcore - for when ffmpeg decided to make this library out of nowhere and have a number of things depend on it
if  ${cross_prefix}pkg-config --exist libavcore 2>$DEVNULL; then
    FFMPEG_LIBS="$FFMPEG_LIBS $(${cross_prefix}pkg-config --libs libavcore)"
    FFMPEG_CFLAGS="$FFMPEG_CFLAGS $(${cross_prefix}pkg-config --cflags libavcore)"
fi

if [ -z "$FFMPEG_LIBS" -a -z "$FFMPEG_CFLAGS" ]; then
    FFMPEG_LIBS="-lavformat -lavcodec -lswscale"
    [ "$postproc" = "yes" ] && FFMPEG_LIBS="$FFMPEG_LIBS -lpostproc"
    for lib in -lavcore -lavutil -lm -lz -lbz2 -lpthread -lavifil32; do
        cc_check "" $lib && FFMPEG_LIBS="$FFMPEG_LIBS $lib"
    done
fi

echo "checking whether linking with FFmpeg or Libav... "
ffmpegORlibav="Libav"
if cpp_check libavcodec/avcodec.h "$FFMPEG_CFLAGS $FFMPEG_LIBS" "LIBAVCODEC_VERSION_MICRO >= 100" ||
   (cpp_check libavcodec/avcodec.h "$FFMPEG_CFLAGS $FFMPEG_LIBS" "LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 47, 100)" &&
    cc_check libavcodec/avcodec.h "$FFMPEG_CFLAGS $FFMPEG_LIBS" "int test = CODEC_ID_G2M;") ; then
    ffmpegORlibav="FFmpeg"
    CPPFLAGS="$CPPFLAGS -DFFMS_USE_FFMPEG_COMPAT"
fi

if ! cc_check libavformat/avformat.h "$FFMPEG_CFLAGS $FFMPEG_LIBS" "avcodec_decode_video2( 0, 0, 0, 0 );" ||
   ! cc_check libswscale/swscale.h "$FFMPEG_CFLAGS $FFMPEG_LIBS" "swscale_version();" ; then
    die "unable to link against $ffmpegORlibav"
fi

# check for optional libpostproc
if [ "$postproc" = "yes" ]; then
    if ! cc_check libpostproc/postprocess.h "$FFMPEG_CFLAGS $FFMPEG_LIBS" "pp_free_mode( 0 );" ; then
        die "unable to link against libpostproc"
    else
        CPPFLAGS="$CPPFLAGS -DFFMS_USE_POSTPROC"
    fi
fi

#find libz
if ! cc_check zlib.h -lz "deflate( 0, 0 );" ; then
    die "unable to link against zlib"
fi

CPPFLAGS="$FFMPEG_CFLAGS $CPPFLAGS"
LDFLAGS="$FFMPEG_LIBS $LDFLAGS"
[ "${LDFLAGS/-lz/}" = "$LDFLAGS" ] && LDFLAGS="$LDFLAGS -lz"

# god do not shadow...
#if cc_check '' -Wshadow ; then
#    CFLAGS="-Wshadow $CFLAGS"
#    CXXFLAGS="-Wshadow $CXXFLAGS"
#fi

if [ "$avs" = "yes" -a "$shared" = "no" ] ; then
    msg="avisynth support is invalid when not building a shared library"
    echo $msg
    log_msg "$msg"
    avs="no"
fi

if [ "$pic" = "yes" ] ; then
    CFLAGS="$CFLAGS -fPIC"
    CXXFLAGS="$CXXFLAGS -fPIC"
    # resolve textrels in the x86 asm
    cc_check stdio.h -Wl,-Bsymbolic && LDFLAGS="$LDFLAGS -Wl,-Bsymbolic"
fi

if [ "$debug" != "yes" -a "$gprof" != "yes" ]; then
    CFLAGS="$CFLAGS -s -fomit-frame-pointer"
    CXXFLAGS="$CXXFLAGS -s -fomit-frame-pointer"
    LDFLAGS="$LDFLAGS -s"
fi
if [ "$debug" = "yes" ]; then
    CFLAGS="-O1 -g $CFLAGS"
    CXXFLAGS="-O1 -g $CXXFLAGS"
else
    CFLAGS="-O3 $CFLAGS"
    CXXFLAGS="-O3 $CXXFLAGS"
fi

# generate config files

version=`./version.sh`
API=$(echo $version | cut -f 1 -d '.')

if [ "$SYS" = "MINGW" ] ; then
    RC="${cross_prefix}windres"

    ffms_version=$(echo $version | sed -e 's/\./,/g')
    version_digits=$(echo $ffms_version | sed -e 's/,/ /g' | wc -w)
    # if digits are missing, add them now
    while [ "$version_digits" -lt 4 ]; do
        ffms_version="${ffms_version},0"
        version_digits=`expr $version_digits + 1`
    done

    ffms_name="FFmpegSource Index"
    cpp_check "" "" "defined(_WIN64)" && ffms_name="$ffms_name x64"

    cat > ffmsindexexe.rc.h << EOF
#define FFMS_NAME "${ffms_name}\0"
#define FFMS_VERSION $ffms_version
#define FFMS_VERSION_STRING "${ffms_version}\0"
#define FFMS_DESCRIPTION "${ffms_name}\0"
EOF

    if [ "$shared" = "yes" ] ; then   

        # now generate the rc file header
        ffms_name="FFmpegSource"
        [ "$avs" = "yes" ] && ffms_name="$ffms_name Avisynth C Plugin" || ffms_name="$ffms_name for Windows"
        cpp_check "" "" "defined(_WIN64)" && ffms_name="$ffms_name x64"
    
        [ "$avs" = "yes" ] && ffms_file="ffms${API}.dll" || ffms_file="libffms-${API}.dll"

        cat > ffmsdll.rc.h << EOF
#define FFMS_NAME "${ffms_name}\0"
#define FFMS_VERSION $ffms_version
#define FFMS_VERSION_STRING "${ffms_version}\0"
#define FFMS_DESCRIPTION "${ffms_name}\0"
#define FFMS_FILE "${ffms_file}\0"
EOF
    fi
fi

rm -f conftest*

cat > config.mak << EOF
prefix=$prefix
exec_prefix=$exec_prefix
bindir=$bindir
libdir=$libdir
includedir=$includedir
API=$API
CC=$CC
CXX=$CXX
CPPFLAGS=$CPPFLAGS
CFLAGS=$CFLAGS
CXXFLAGS=$CXXFLAGS
LDFLAGS=$LDFLAGS
AR=$AR
RANLIB=$RANLIB
STRIP=$STRIP
EXE=$EXE
DEVNULL=$DEVNULL
AVISYNTH=$avs
SOFLAGS_USER=$SOFLAGS
SYS=$SYS
FFMS_USE_POSTPROC=$postproc
RC=$RC
EOF

if [ "$shared" = "yes" ]; then
    if [ "$SYS" = "MINGW" ]; then
        # avisynth plugins have a generally different name than other things
        if [ "$avs" = "yes" ] ; then
            echo "SONAME=ffms${API}.dll" >> config.mak
            echo 'SOFLAGS=-Wl,--out-implib,$(IMPLIBNAME) -Wl,--enable-auto-image-base -Wl,--export-all-symbols' >> config.mak
        else
            echo "SONAME=libffms-${API}.dll" >> config.mak
            echo 'SOFLAGS=-Wl,--out-implib,$(IMPLIBNAME) -Wl,--enable-auto-image-base' >> config.mak
        fi
        echo "IMPLIBNAME=libffms-${API}.dll.a" >> config.mak
    elif [ "$SYS" = "MACOSX" ]; then
        echo "SOSUFFIX=dylib" >> config.mak
        echo "SONAME=ffms.$API.dylib" >> config.mak
        echo 'SOFLAGS=-dynamiclib -Wl,-single_module -Wl,-read_only_relocs,suppress -install_name $(DESTDIR)$(libdir)/$(SONAME)' >> config.mak
    elif [ "$SYS" = "SunOS" ]; then
        echo "SOSUFFIX=so" >> config.mak
        echo "SONAME=ffms.so.$API" >> config.mak
        echo 'SOFLAGS=-Wl,-h,$(SONAME)' >> config.mak
    else
        echo "SOSUFFIX=so" >> config.mak
        echo "SONAME=ffms.so.$API" >> config.mak
        echo 'SOFLAGS=-Wl,-soname,$(SONAME)' >> config.mak
    fi
    echo 'default: $(SONAME)' >> config.mak
fi

cat > ffms.pc << EOF
prefix=$prefix
exec_prefix=$exec_prefix
libdir=$libdir
includedir=$includedir

Description: The Fabulous FM Library
Requires: libavformat libavcodec libswscale libpostproc libavutil
Version: $version
Libs: -L$libdir -lffms -lz
Cflags: -I$includedir
EOF

cat > conftest.log <<EOF
avs:        $avs
debug:      $debug
gprof:      $gprof
PIC:        $pic
postproc:   $postproc
shared:     $shared
EOF

echo >> config.log
cat conftest.log >> config.log
cat conftest.log
rm conftest.log

echo
echo "You can run 'make' now."
